package poker;

import java.awt.Color;
import java.util.LinkedList;
import javax.swing.JOptionPane;

/**
 * This class contains the main program.
 *
 * @author Antti M. Harittu
 */
public class Poker {
    
    /** The deck */
    static LinkedList<Card> deck = new LinkedList<Card>();
    
    /** Player p1. The computer. */
    static Player p1;
    
    /** Player p2. User. */
    static Player p2;
    
    /** Has the round just started? */
    static boolean beginning = true;
    
    /** 
     * How many times a card has been changed during a round. Allowed values:
     * [0, 2].
     */
    static int countDraws = 0;
    
    /**
     * This method calls methods for asking the user to input a nickname,
     * initializing the Window and creates the players and the deck.
     *
     * @param args
     */
    public static void main(String[] args) {
        deck = nextDeck();
        p1 = new Player("Computer");
        p2 = new Player(askName());
        Window gui = new Window();
        gui.setVisible(true);
        Window.capP1.setText(Poker.p1.getN());
        Window.capP2.setText(Poker.p2.getN());
    } // end main

    /**
     * The method creates a JOptionPane for asking the user to input a nickname.
     *
     * @return
     */
    private static String askName() {
        String st = JOptionPane.showInputDialog(null,
                "What is your name: ",
                "Poker", JOptionPane.PLAIN_MESSAGE);

        while (st != null && st.length() > 31) {
            st = JOptionPane.showInputDialog(null,
                    "Maximun 30 characters: ",
                    "Poker", JOptionPane.ERROR_MESSAGE);
        }
        if (st == null || st.length() == 0) { st = "Player2"; }
        return st;
    } // askName

    /**
     * This is method is called from the class Window, when the play-button is
     * clicked. If the round is just about to begin, variables are initialized.
     * Otherwise a method is called for notifying the user about the winner of
     * the round.
     */
    public static void play() {
        if (beginning) {
            begin();
            beginning = false;
        } else {
            notifyWinner();
        }
    } // end play

    /**
     * This method contains operations for beginning the round. The method think
     * is called from the class Computer and other methods are called for
     * updating the variables of the Window.
     */
    private static void begin() {
        Poker.setCards();
        setVariables("");
        hideHandP1();
        showHandP2();
        countDraws = 0;
        notifyP1(Computer.think());
    } // end begin

    /** This method sets the both players hands. */
    private static void setCards() {
        p1.setHand();
        p2.setHand();
    } // end setCards

    /**
     * This method checks who has won and returns the result as an array.
     * 
     * @return {winner, hand}
     */
    public static int[] checkWinner() {
        int v1[] = Hands.winningHand(p1.getHand());
        int v2[] = Hands.winningHand(p2.getHand());
        // Both players have the same winning hand.
        if (v1[0] == v2[0]) {
            // Standoff
            if (v1[1] == v2[1]) {
                return new int[]{0, v1[0]};
            } else {
                if (v1[1] > v2[1]) {
                    return new int[]{1, v1[0]};
                } else {
                    return new int[]{2, v1[0]};
                }
            }
        }
        // Who has the most valuable combination?
        if (v1[0] < v2[0]) {
            return new int[]{1, v1[0]};
        } else {
            return new int[]{2, v2[0]};
        }
    } // end checkWinner

    /**
     * This method notifies the user through GUI announcing the winner.
     */
    private static void notifyWinner() {
        int[] t = Poker.checkWinner();
        String st = "";
        if (t[0] == 0) { st = "Standoff with "; }
        if (t[0] == 1) {
            Poker.p1.setWin();
            st = Poker.p1.getN() + " won with ";
        }
        if (t[0] == 2) {
            Poker.p2.setWin();
            st = Poker.p2.getN() + " won with ";
        }
        String[] stK = {
            "a straight flush",
            "a flush",
            "a four of a kind",
            "a fullhouse",
            "a three of a kind",
            "two pairs",
            "a pair",
            "a high card"
        };
        st += stK[t[1]] + ".";
        beginning = true;
        setVariables(st);
        showHandP1();
    } // end checkWinner
    
    /**
     * This method returns a list containing 52 Card-components. The returned
     * deck is shuffled.
     *
     * @return
     */
    public static LinkedList<Card> nextDeck() {
        char[] suits = {'S', 'H', 'D', 'C'};
        for (int m = 0; m < 4; m++) {
            for (int l = 2; l < 15; l++) {
                deck.add((int) (Math.random() * (deck.size() + 1)),
                        new Card(suits[m], l));
            }
        }
        return deck;
    } // end nextDeck

    /**
     * This method draws one card from the deck. If the deck is empty, the
     * nextDeck()-method is called.
     *
     * @return
     */
    public static Card draw() {
        if (deck.size() == 0) {
            deck = nextDeck();
        }
        return deck.removeFirst();
    } // end draw

    /**
     * The method updates the variables in the class Window.
     *
     * @param st
     */
    private static void setVariables(String st) {
        Window.deckGUI.setText("Deck: "
                + Poker.deck.size());
        Window.winsGUI.setText("Wins: "
                + Poker.p1.getW() + "/"
                + Poker.p2.getW());
        Window.notifyGUI.setText(st);
    } // end setVariables

    /**
     * This method shows the hand of player p1.
     */
    private static void showHandP1() {
        Color p = new Color(255, 0, 0);
        Color m = new Color(0, 0, 0);

        String a = Poker.p1.getCard(0).getPic();
        String b = Poker.p1.getCard(1).getPic();
        String c = Poker.p1.getCard(2).getPic();
        String d = Poker.p1.getCard(3).getPic();
        String e = Poker.p1.getCard(4).getPic();

        if (whichColor(a)) {
            Window.card1_P1.setForeground(p);
        } else {
            Window.card1_P1.setForeground(m);
        }
        Window.card1_P1.setText(a);

        if (whichColor(b)) {
            Window.card2_P1.setForeground(p);
        } else {
            Window.card2_P1.setForeground(m);
        }
        Window.card2_P1.setText(b);

        if (whichColor(c)) {
            Window.card3_P1.setForeground(p);
        } else {
            Window.card3_P1.setForeground(m);
        }
        Window.card3_P1.setText(c);

        if (whichColor(d)) {
            Window.card4_P1.setForeground(p);
        } else {
            Window.card4_P1.setForeground(m);
        }
        Window.card4_P1.setText(d);

        if (whichColor(e)) {
            Window.card5_P1.setForeground(p);
        } else {
            Window.card5_P1.setForeground(m);
        }
        Window.card5_P1.setText(e);
    } // end showHandP1

    /** This method hides the hand of player p1. */
    private static void hideHandP1() {
        Color m = new Color(0, 0, 0);
        Window.card1_P1.setForeground(m);
        Window.card1_P1.setText("?");
        Window.card2_P1.setForeground(m);
        Window.card2_P1.setText("?");
        Window.card3_P1.setForeground(m);
        Window.card3_P1.setText("?");
        Window.card4_P1.setForeground(m);
        Window.card4_P1.setText("?");
        Window.card5_P1.setForeground(m);
        Window.card5_P1.setText("?");
    } // end hideHandP1

    /**
     * This method shows the hand of player p2.
     */
    private static void showHandP2() {
        Color p = new Color(255, 0, 0);
        Color m = new Color(0, 0, 0);
        String a = Poker.p2.getCard(0).getPic();
        String b = Poker.p2.getCard(1).getPic();
        String c = Poker.p2.getCard(2).getPic();
        String d = Poker.p2.getCard(3).getPic();
        String e = Poker.p2.getCard(4).getPic();

        if (whichColor(a)) {
            Window.card1_P2.setForeground(p);
        } else {
            Window.card1_P2.setForeground(m);
        }
        Window.card1_P2.setText(a);

        if (whichColor(b)) {
            Window.card2_P2.setForeground(p);
        } else {
            Window.card2_P2.setForeground(m);
        }
        Window.card2_P2.setText(b);

        if (whichColor(c)) {
            Window.card3_P2.setForeground(p);
        } else {
            Window.card3_P2.setForeground(m);
        }
        Window.card3_P2.setText(c);

        if (whichColor(d)) {
            Window.card4_P2.setForeground(p);
        } else {
            Window.card4_P2.setForeground(m);
        }
        Window.card4_P2.setText(d);

        if (whichColor(e)) {
            Window.card5_P2.setForeground(p);
        } else {
            Window.card5_P2.setForeground(m);
        }
        Window.card5_P2.setText(e);
    } // end showHandP2

    /**
     * This method checks the color of a card. True is returned if the card
     * should be displayed as red.
     *
     * @param s
     * @return
     */
    private static boolean whichColor(String s) {
        char c = s.charAt(0);
        if (c == '♥' || c == '♦') {
            return true;
        }
        return false;
    } // end whichColor

    /**
     * This method notifies the user through the GUI about the actions of the
     * player p1.
     *
     * @param i
     */
    private static void notifyP1(int i) {
        String st = Poker.p1.getN();
        if (i == 0) {
            st += " didn't draw any cards.";
        }
        if (i == 1) {
            st += " replaced one card.";
        }
        if (i == 2) {
            st += " replaced two cards.";
        }
        Window.notifyGUI.setText(st);
    } // end notifyP1

    /**
     * This method is called with a mouseclick of the GUIs' cards. The method
     * updates the variables.
     *
     * @param i
     */
    public static void actionCard(int i) {
        if (countDraws < 2) {
            Poker.p2.setCard(i);
            showHandP2();
            Window.deckGUI.setText("Deck: "
                + Poker.deck.size());
            countDraws++;
        }
    } // end actionCard
} // end Poker